package com.mo.sys.service.aspect;


import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.mo.common.annotation.RequiredLog;
import com.mo.sys.pojo.SysLog;
import com.mo.sys.service.SysLogService;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.Date;

/**
 * 在Spring AOP应用中，基于@Aspect注解描述的
 *  * 类型为一个切面类型，此类中要封装切入点及通知方法的定义
 *  * 1)切入点:要切入扩展业务逻辑的一些目标方法集合(例如使用了特点注解描述的方法)
 *  * 2)通知：封装了扩展业务逻辑的一个方法(spring中也可使用特定注解进行描述)
 */
@Slf4j
@Aspect
@Component
public class SysLogAspect {


    /**
     * @Pointcut 注解用于定义切入点
     * @annotation（注解）为切入点表达式， 后续由此RequiredLog注解描述的方法为切入点方法
     */
    @Pointcut("@annotation(com.mo.common.annotation.RequiredLog)")
    public void doLog() {
    }//承载切入点的定义


    /**
     * 定义通知方法
     *
     * @return 目标方法的执行结果
     * @throws Throwable
     * @Around 描述方法可以在切入点执行之前和之后进行业务拓展
     * jP连接点对象，此对象封装了要执行的目标方法信息
     * 可以通过连接点对象调用目标方法
     */

    @Around("doLog()")
    public Object doAround(ProceedingJoinPoint jp) throws Throwable {
        System.out.println("SysLogAspect.@Around.before");
        long t1 = System.currentTimeMillis();
        log.info("method start {}", t1);
        try {
            //执行目标方法
            Object result = jp.proceed(); //通过反射，调用目标方法

            long t2 = System.currentTimeMillis();
            log.info("日志记录opertime:{}", t2 - t1);
            return result;//执行结果
        } catch (Throwable e) {
            e.printStackTrace();
            long t2 = System.currentTimeMillis();
            log.info("exception:{}", e.getMessage());
            throw e;
        }
    }
    @Lazy
        @Autowired
        public SysLogService sysLogService;
        private void doSaveLogInfo (ProceedingJoinPoint jp,long time, Throwable e) throws
        NoSuchMethodException, JsonProcessingException {
            //1.获取用户行为日志
            //1.1获取登录用户信息
            String username = "tony";//后续是系统的登录用户
            //1.2获取登录用户的ip地址
            String ip = "192.168.100.11";//后续可以借助三方工具类
            //1.3获取用户操作
            //1.3.1获取方法所在类的字节码对象(目标对象对应的字节码对象)
            Class<?> cls = jp.getTarget().getClass();
            //1.3.2获取注解描述的方法对象(字节码对象，方法名，参数列表)
            Signature signature = jp.getSignature();
            // System.out.println("signature="+signature.getClass().getName());//MethodSignatureImpl
            //  MethodSignatureImpl
            MethodSignature methodSignature = (MethodSignature) signature;
            //Method targetMethod=methodSignature.getMethod();//cglib
            Method targetMethod =//cglib,jdk
                    cls.getDeclaredMethod(methodSignature.getName(),
                            methodSignature.getParameterTypes());
            //System.out.println("targetMethod="+targetMethod);
            //1.3.3获取RequiredLog注解
            RequiredLog requiredLog = targetMethod.getAnnotation(RequiredLog.class);
            String operation = requiredLog.operation();
            //1.4获取方法声明信息
            String method = cls.getName() + "." + targetMethod.getName();
            //1.5获取方法执行时传入的实际参数
            Object[] args = jp.getArgs();//实际参数
            String params = new ObjectMapper().writeValueAsString(args);//转json
            //1.6获取状态信息
            Integer status = e == null ? 1 : 0;//1表示ok
            //1.7获取错误信息
            String error = e == null ? "" : e.getMessage();
            //2.封装用户行为日志
            SysLog sysLog = new SysLog();
            sysLog.setUsername(username);
            sysLog.setIp(ip);
            sysLog.setCreatedTime(new Date());
            sysLog.setOperation(operation);
            sysLog.setMethod(method);
            sysLog.setParams(params);
            sysLog.setStatus(status);
            sysLog.setError(error);
            sysLog.setTime(time);
            //将日志写入到数据库
            log.info("user log {}", new ObjectMapper().writeValueAsString(sysLog));
            sysLogService.savelogs(sysLog);
        }
    }



/**
    @Autowired
    private SysLogService sysLogService;
    private void doSaveLogInfo(ProceedingJoinPoint joinPoint,long time,Throwable e) throws NoSuchMethodException, JsonProcessingException {

        //获取用户行为日志
          //1获取登录用户信息
        String username="bingomo";//后续是系统的登录用户
        //2获取登录用户的ip地址
        String ip="192.168.100.11";//
        //3获取用户操作
            //获取方法所在的类的字节码对象
            //获取注解描述的方法对象（方法名，方法参数）
            //获取RequiredLog注解
            //String operation=null;
        Class<?>cls=joinPoint.getTarget().getClass();  //获取目标类
        Signature signature= joinPoint.getSignature();//获取签名
        //

       // signature.getClass().getName(); //获取的对象是谁？
       // System.out.println("签名"+ signature.getClass().getName());

       MethodSignature ms= (MethodSignature) signature;

        Method targetMethod=
       cls.getDeclaredMethod(ms.getName(),ms.getParameterTypes());

       RequiredLog annotation=
        targetMethod.getAnnotation(RequiredLog.class);
        //获取到注解的参数
       String  operation= annotation.operation();
        //获取方法名
        String method=cls.getName()+"."+targetMethod.getName();
        //获取到传入的实际参数
        Object[] args=joinPoint.getArgs();
        String params=new ObjectMapper().writeValueAsString(args);
       //获取状态信息
        Integer status=e==null?1:0; //1表示ok
        //获取错误信息
        String error=e==null?"":e.getMessage();

        //封装用户行为日志
        SysLog sysLog=new SysLog();
        sysLog.setUsername(username);
        sysLog.setIp(ip);
        sysLog.setCreatedTime(new Date());
        sysLog.setOperation(operation);
        sysLog.setMethod(method);
        sysLog.setParams(params);
        sysLog.setStatus(status);
        sysLog.setError(error);
        sysLog.setTime(time);

        //将日志写入到数据库
        log.info("user log{}",new ObjectMapper().writeValueAsString(sysLog));
        sysLogService.savelogs(sysLog);


    }
*/

